#include "Common/DataStructureMacro.h"
#include "Common/Information.h"
#include "SpeedModel.h"
#include "ssas_api.h"
#define LOG_TAG "SPEED"
#include "log_api.h"

typedef enum {
    FAULT,
    RUNNING,
    IDLE,
    RECOVERING,
} State;

typedef enum {
    CUSHION_UP,    //向上缓冲状态
    CUSHION_DOWN,  //乡下缓冲
    STEADY,     //稳定状态
} ChildState;

typedef enum {
    EV_FAULT,
    EV_RUNNING,
    EV_RECOVER_FINISH,
} Event;

typedef struct 
{
    int  cushionTimeoutCount_;
    ChildState state_;
} SpeedWorkingData;

typedef struct 
{
    State             currentState_;
    SpeedWorkingData  runningChildState_;
    SpeedWorkingData  faultChildState_;
} StateMachine;

static StateMachine sm;
static int rawSpeed;
static Option_Int showSpeed;
static Option_Int showText;
static uint8_t    view_visible_mask_ = 0;

static void init()
{
    sm.currentState_ = IDLE;
    sm.runningChildState_.state_ = CUSHION_DOWN;
    sm.runningChildState_.cushionTimeoutCount_ = 0;
    sm.faultChildState_.state_ = CUSHION_DOWN;
    sm.faultChildState_.cushionTimeoutCount_ = 0;
    showSpeed.update_ = false;
    showSpeed.value_ = 0;
    showText.update_ = false;
    showText.value_ = 0;
    rawSpeed = 0;   //read form can
}

static void release()
{
}

bool updateRawSpeed(Option_Int* speed)
{
    bool result = false;
    Std_ReturnType ret = E_NOT_OK;
    do
    {
        if(COM_MSG_TIMEOUT == get_message_state(COM_IC_ANTILOCK_BRAKE_AND_TC_STATUS_HS))
        {
            // LOG_D("CANIF_IC_ANTILOCK_BRAKE_AND_TC_STATUS_HS timeout\n");
            break;
        }

        uint16_t speed_v = 0;
        ret = Com_ReceiveSignal(COM_SID_VehSpdAvgDrvnV_ABS, &speed_v);
        if(E_NOT_OK == ret || 1 == speed_v)
        {
            // LOG_D("COM_SID_VehSpdAvgDrvnV_ABS Invaild\n");
            break;
        }

        //checksum todo

        rawSpeed = 0;
        ret = Com_ReceiveSignal(COM_SID_VehSpdAvgDrvn_ABS, &rawSpeed);
        if(E_NOT_OK == ret)
        {
            LOG_D("COM_SID_VehSpdAvgDrvn_ABS Invaild\n");
            break;
        }
        else
        {
            if(speed->value_ != rawSpeed)
            {
                speed->value_ = rawSpeed;
                speed->update_ = true;
            }
            memcpy(&showText, &speed, sizeof(Option_Int));
            result = true;
        }
    } while (false);


    return result;
}

static void leaveFault()
{
    sm.faultChildState_.state_ = CUSHION_DOWN;
    sm.faultChildState_.cushionTimeoutCount_ = 0;
}

static void executeFault()
{
    if(sm.faultChildState_.state_ == CUSHION_DOWN)
    {
        if(showSpeed.value_ > 0)
        {
            showSpeed.value_ -= 100;
            if(showSpeed.value_ < 0)
            {
                showSpeed.value_ = 0;
                sm.faultChildState_.state_ = STEADY;
            }
            showSpeed.update_ = true;
            memcpy(&showText, &showSpeed, sizeof(Option_Int));
        }

        sm.faultChildState_.cushionTimeoutCount_++;
        if(sm.faultChildState_.cushionTimeoutCount_ > 90)
        {
            sm.faultChildState_.state_ = STEADY;
        }
    }
    else
    {
        //ignore
    } 
}

static void leaveRunning()
{
    sm.runningChildState_.state_ = CUSHION_DOWN;
    sm.runningChildState_.cushionTimeoutCount_ = 0;
}

static void entryRunning()
{
    if(showSpeed.value_ > rawSpeed)
    {
        sm.runningChildState_.state_ = CUSHION_DOWN;
    }
    else if(showSpeed.value_ < rawSpeed)
    {
        sm.runningChildState_.state_ = CUSHION_UP;
    }
    else
    {
        sm.runningChildState_.state_ = STEADY;
    }
}

static void executeRunning()
{
    switch(sm.runningChildState_.state_)
    {
        case STEADY:
        {
            showSpeed.value_ = rawSpeed;
            showSpeed.update_ = true;
            memcpy(&showText, &showSpeed, sizeof(Option_Int));
            break;
        }
        case CUSHION_UP:
        {
            if(showSpeed.value_ < rawSpeed)
            {
                showSpeed.value_ += 100;
                if(showSpeed.value_ >= rawSpeed)
                {
                    showSpeed.value_ = rawSpeed;
                    sm.runningChildState_.state_ = STEADY;
                }
                showSpeed.update_ = true;
                memcpy(&showText, &showSpeed, sizeof(Option_Int));
            }

            sm.runningChildState_.cushionTimeoutCount_++;
            if(sm.runningChildState_.cushionTimeoutCount_ > 90)
            {
                sm.runningChildState_.state_ = STEADY;
            }
            break;
        }
        case CUSHION_DOWN:
        {
            if(showSpeed.value_ > rawSpeed)
            {
                showSpeed.value_ -= 100;
                if(showSpeed.value_ <= rawSpeed)
                {
                    showSpeed.value_ = rawSpeed;
                    sm.runningChildState_.state_ = STEADY;
                }
                showSpeed.update_ = true;
                memcpy(&showText, &showSpeed, sizeof(Option_Int));
            }

            sm.runningChildState_.cushionTimeoutCount_++;
            if(sm.runningChildState_.cushionTimeoutCount_ > 90)
            {
                sm.runningChildState_.state_ = STEADY;
            }
            break;
        }
        default:
            break;
    }
}

static void run()
{
    if(view_visible_mask_)
    {
        bool ret = updateRawSpeed(&showSpeed);
        switch (sm.currentState_)
        {
            case IDLE:
            {
                if(ret)
                {
                    sm.currentState_ = RUNNING;
                }
                else
                {
                    sm.currentState_ = FAULT;
                }
                break;
            }

            case FAULT:
            {
                if(ret)
                {
                    leaveFault();
                    sm.currentState_ = RUNNING;
                    entryRunning();
                }
                else
                {
                }
                break;
            }

            case RUNNING:
            {
                if(ret)
                {
                }
                else
                {
                    leaveRunning();
                    sm.currentState_ = FAULT;
                }
                break;
            }
        
            default:
                break;
        }

        //
        switch (sm.currentState_)
        {
            case FAULT:
            {
                executeFault();
                break;
            }

            case RUNNING:
            {
                executeRunning();
                break;
            }
            
            default:
                break;
        }

        {
            uint32_t rawSendSpeed = (uint32_t)showSpeed.value_;
            Std_ReturnType ret = Com_SendSignal(COM_SID_DispVehSpd, &rawSendSpeed);
            if(ret == E_NOT_OK)
            {
                LOG_W("Com_SendSignal fail, %d\n", COM_SID_DispVehSpd);
            }
        }
    }
    
    
}

SpeedModel g_SpeedModelInstance = {
    // ImeterModel
    {
        init,
        run,
        release,
        MIN_PERIOD,
    },
};

// ----------------------------------View------------------------------
static float calculatedShowSpeed(float raw_speed)
{
    volatile float out = 0.0f;
    if(raw_speed >= 0.0f && raw_speed < 10.0f)
    {
        out =  raw_speed * 1.22;
    }
    else if(raw_speed >= 10.0f && raw_speed < 100.0f)
    {
        out =  raw_speed * 1.02 + 2.0f;
    }
    else if(raw_speed >= 100.0f && raw_speed < 116.0f)
    {
        out =  raw_speed * 1.03f + 1.0f;
    }
    else
    {
        out =  120.0f;
    }

    if(out > 100.0f)
    {
        out = 100.1f;
    }

    return out;
}

void getShowSpeed(float* out)
{
    float speed = (float)(showSpeed.value_) * 0.015625;
    *out = calculatedShowSpeed(speed);
}

void refresh_SpeedMeterView(ItuElement* elememt, bool isUnconditional)
{
    float speed = (float)showSpeed.value_ * 0.015625;
    if(showSpeed.update_)
    {
        ituMeterSetValue((ITUMeter *)elememt->widget_, calculatedShowSpeed(speed));
        showSpeed.update_ = false;
    }
    else
    {
        // LOG_D("not update : %f\n", speed);
    }
}

void reporting_self_validity_SpeedMeterView(ItuElement* elememt)
{
    uint8_t mask = (elememt && elememt->isVaild_) ? 0x01 : 0x00;
    view_visible_mask_ <<= 1;
    view_visible_mask_ |= 1;
}

void refresh_SpeedTextView(ItuElement* elememt, bool isUnconditional)
{
    if(showText.update_)
    {
        char str[20];
        float speed = (float)showText.value_ * 0.015625;
        memset(str, 0, 20);
        snprintf(str, sizeof(str), "%d", (int)calculatedShowSpeed(speed));
        ituTextSetString(elememt->widget_, str);
        showText.update_ = false;
    }
}

void reporting_self_validity_SpeedTextView(ItuElement* elememt)
{
    uint8_t mask = (elememt && elememt->isVaild_) ? 0x01 : 0x00;
    view_visible_mask_ <<= 1;
    view_visible_mask_ |= 1;
}

void refresh_BatteryView(ItuElement* elememt, bool isUnconditional)
{
    // TODO
}

void reporting_self_validity_BatteryView(ItuElement* elememt)
{
    
}

void refresh_Odo1View(ItuElement* elememt, bool isUnconditional)
{
    // TODO
}

void reporting_self_validity_Odo1View(ItuElement* elememt)
{
    
}

void refresh_Odo2View(ItuElement* elememt, bool isUnconditional)
{
    // TODO
}

void reporting_self_validity_Odo2View(ItuElement* elememt)
{
    
}

void refresh_Odo3View(ItuElement* elememt, bool isUnconditional)
{
    // TODO
}

void reporting_self_validity_Odo3View(ItuElement* elememt)
{
    
}

void refresh_StallView(ItuElement* elememt, bool isUnconditional)
{
    // TODO
}

void reporting_self_validity_StallView(ItuElement* elememt)
{
    
}

void refresh_RadiatorView(ItuElement* elememt, bool isUnconditional)
{
    // TODO
}

void reporting_self_validity_RadiatorView(ItuElement* elememt)
{
    
}